﻿using System.IO;
using System;
using Microsoft.VisualStudio.SharePoint;
using Microsoft.VisualStudio.SharePoint.Deployment;
using Microsoft.VisualStudio.SharePoint.Packages;
using System.ComponentModel.Composition;
using System.Linq;
using System.DirectoryServices;

using System.Diagnostics;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.ComponentModel.Design;
using System.Xml;
using SPVSX.Common;
using EnvDTE;
using EnvDTE80;
using Microsoft.Win32;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.OLE.Interop;
using Microsoft.VisualStudio.Shell;

namespace SPVSX.DeploymentExtensions.QuickDeployment
{
    /// <summary>
    /// TODO: COMMENT
    /// 
    /// This code is a WIP and is in need of improved commenting, exception handling, and potentially
    /// factoring.  Please be nice.
    /// 
    /// Though this code is Open Source, in good faith it is requested that you consult the original author(s)
    /// before changing or re-using it for any public endeavour intended to provide similar functionality, or
    /// to fix simple bugs.  In other words, if you want to create SPVSX2, please let us know first.
    /// </summary>
    /// <remarks>@author Matt Smith, http://blog.mattsmith.co.nz</remarks>
    public class SharePointProjectFeatureArtefact : QuickCopyableSharePointArtefact
    {
        private ISharePointProjectFeature feature = null;
        private IEnumerable<QuickCopyableSharePointArtefact> kids = null;
        private Dictionary<string, string> tokens = null;

        public SharePointProjectFeatureArtefact(ISharePointProjectFeature feature)
        {
            this.feature = feature;
        }

        public string FeatureFolderName
        {
            get
            {
                // Even though a feature can be included in multiple projects/packages, the tokenized feature name is 
                // always replaced with the VS project the feature is actually contained in.
                string featureFolderName = feature.Model.DeploymentPath;
                featureFolderName = featureFolderName.Replace("$SharePoint.Project.FileNameWithoutExtension$", feature.Project.Name);
                featureFolderName = featureFolderName.Replace("$SharePoint.Feature.FileNameWithoutExtension$", Path.GetFileNameWithoutExtension(feature.FullPath));
                return featureFolderName;
            }
        }

        public override IEnumerable<QuickCopyableSharePointArtefact> ChildArtefacts
        {
            get
            {
                if (kids == null)
                {
                    List<QuickCopyableSharePointArtefact> children = new List<QuickCopyableSharePointArtefact>();

                    // Get SPIs in this feature - will only include those that are set to be packaged.
                    foreach (ISharePointProjectItem spi in feature.ProjectItems)
                    {
                        children.Add(new SharePointProjectItemArtefact(spi));
                    }

                    kids = children;
                }
                return kids;
            }
        }

        public override bool IsPackaged(ISharePointProjectService service)
        {
            return feature.IsPartOfAnyProjectPackage(service);
        }

        public override bool IsPackaged(ISharePointProject project)
        {
            return feature.IsPartOfProjectPackage(project);
        }

        public override IEnumerable<ISharePointProject> GetPackagedProjects(ISharePointProjectService service)
        {
            return feature.GetProjectsWhereInPackage(service);
        }

        public override Dictionary<string, string> Tokens
        {
            get
            {
                if (tokens == null)
                {
                    tokens = new Dictionary<string, string>();
                    tokens.Add("SharePoint.Feature.FileName", Path.GetFileName(feature.FeatureFile.Name));
                    tokens.Add("SharePoint.Feature.FileNameWithoutExtension", Path.GetFileNameWithoutExtension(feature.FeatureFile.Name));
                    tokens.Add("SharePoint.Feature.DeploymentPath", this.FeatureFolderName);
                    tokens.Add("SharePoint.Feature.Id", feature.Id.ToString());
                }

                return tokens;
            }
        }

        public override void QuickCopy(SharePointPackageArtefact packageProject, bool requiresQuickPackage)
        {
            // We are directly deploying just this feature and have not been called by our parent.
            if (feature.IsPartOfProjectPackage(packageProject.Project))
            {
                // Pass in the package itself as the parent.
                this.QuickCopy(packageProject, packageProject, requiresQuickPackage);
            }
        }

        public override void QuickCopy(SharePointPackageArtefact packageProject, QuickCopyableSharePointArtefact parentArtefact, bool requiresQuickPackage)
        {
            if (parentArtefact == null)
            {
                throw new NotSupportedException();
            }
            else if (parentArtefact is SharePointPackageArtefact)
            {
                string sourcePathBase = packageProject.BasePackagePath;
                string featureFolderName = this.FeatureFolderName;

                OutputWindowLogger.Instance.WriteLine("------ Quick Copying Feature: " + this.FeatureFolderName + " ------", LogCategory.Status);

                // Feature.xml must first be Quick Copied.
                if (requiresQuickPackage)
                {
                    // Tokens consist of those from this package, and feature.
                    Dictionary<string, string> allTokens = new Dictionary<string, string>();
                    allTokens.AddRange(packageProject.Tokens);
                    allTokens.AddRange(this.Tokens);

                    // TODO: Merge feature.feature.
                    OutputWindowLogger.Instance.WriteLine("WARNING: Quick packaging of changes to Feature.feature is not yet supported.  The last packaged version of the file will be copied.", LogCategory.Warning);
                    //QuickDeploymentUtilities.CopyFileWithTokenReplacement(packageProject.Project, file.Name, originalFileProjectRelative, sourcePackagePathProjectRelative, allTokens);
                }

                QuickDeploymentUtilities.CopyFile(packageProject.Project, "Feature.xml", Path.Combine(sourcePathBase, featureFolderName), "{SharePointRoot}\\Template\\Features\\" + featureFolderName);

                // Process items in features.  Note that we are only processing items that have been set to be packaged.
                foreach (SharePointProjectItemArtefact spi in this.ChildArtefacts.Select(ca => ca as SharePointProjectItemArtefact))
                {
                    spi.QuickCopy(packageProject, this, requiresQuickPackage);
                }
            }
            else
            {
                throw new NotSupportedException();
            }
        }
    }
}